EKSのAuto Scalingを試してみた
こんにちは。EKS Workshop
で実際に手を動かしながら機能を学んでいます。
やはり手を動かしながら学べるので本当に楽しいですよね。
さて今回はEKS Workshopでも取り扱っていた 「Horizontal Pod Autoscaler (HPA)」と「Cluster Autoscaler (CA)」を 実際に試してみたのでブログに書いてみました。
Horizontal Pod Autoscaler (HPA) を試してみる
さてまずはHPAから試していきます。
HPAはKubernetesのリソースの1つで、CPU使用率、API Objectのメトリクスなどをモニタリングし、
スケーリングが必要になったタイミングで、Replication ControllerやDeploymentなどのPod数をスケーリングします。
DaemonSetのようにスケールしないしない物に関してはHPAの対象とすることはできません。
概要を抑えたところで実際に手を動かしていきましょう。
環境
- Kubernetes: 1.14
- helm: 3.0.0
- eksctl: 0.10.2
1. クラスタの作成
eksctlを使って東京リージョンにさくさくっと作り上げます。
$ export AWS_DEFAULT_REGION=ap-northeast-1 $ eksctl create cluster \ --name=eksworkshop-hpa \ --nodes=3 \ --node-type=t3.small
2. Metrics Serverのインストール
HPAがスケーリングの指示をするにあたって、メトリクスを収集する必要があります。
Kubernetesでは一般的には
Metrics Server
を使用します。
今回はMetrics ServerをHelmを使用してデプロイします。
またこちらの手順
でHelmを使用せずにデプロイすることもできます。
$ helm install stable/metrics-server \ --generate-name \ --namespace kube-system NAME: metrics-server-1574319962 LAST DEPLOYED: Thu Nov 21 16:06:04 2019 NAMESPACE: kube-system STATUS: deployed REVISION: 1 NOTES: The metric server has been deployed. In a few minutes you should be able to list metrics using the following command: kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"
こちらもEKSクラスタと同様にサクッとデプロイができました。
表示されたコマンドを実行して問題なく動作しているかの確認をします。
$ kubectl get apiservice v1beta1.metrics.k8s.io -o yaml apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: creationTimestamp: "2019-11-21T07:06:04Z" labels: app: metrics-server chart: metrics-server-2.8.8 ~~~
一部表示を端折っていますが問題なさそうですね。
3. サンプルアプリケーションのデプロイ
GETリクエストに対して「ok!」とレスポンスを返すアプリケーションを元にDeploymentの作成とServiceで公開します。
$ kubectl run php-apache --image=k8s.gcr.io/hpa-example --requests=cpu=200m --expose --port=80 service/php-apache created deployment.apps/php-apache created
4. HPAのデプロイ
次にkubectl autoscale
を実行してHPAをデプロイします。
先ほど作成したDeploymentで稼働しているPodのCPU使用率が平均して50%になるようにスケーリングを行います。
$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
HPAの状況を確認してみます。
アプリケーションに対して負荷をかけていない状態なのでメトリクスは0%/50%
でRelicas
も1になっています。
$ kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 0%/50% 1 10 1 3m32s
5. スケーリングさせる
別途Busyboxを用意してそこから先ほど作成したアプリケーションに対して負荷をかけます。
$ while true; do wget -q -O - http://php-apache; done OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!
アプリケーションはOK!
とレスポンスを返すので問題なく動作してますね。
この時HPAの状態を確認してみましょう。
$ kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 271%/50% 1 10 1 5m
スケールアウトできておらず、1つのPodにかなりの負荷がかかっています。
この状態から暫く時間が経ってからもう一度確認します。
$ kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 47%/50% 1 10 10 8m8s
十分にスケールされてCPU負荷も50%付近を保っています。
ここでBusyboxからのリクエストを停止させます。
$ kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 0%/50% 1 10 10 10m
この状態から数分経過した後に、Pod数が1つに戻ります。
$ kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 0%/50% 1 10 1 15m
thrashing
と呼ばれる、スケール管理時にメトリクスによって頻繁なレプリカ数の変化が発生する可能性があります。
Kubernetesではこれを防ぐためにHPAでスケールインするまでの待機時間を設定することができ、
これにより設定されているためにスケールインに関しては大きく時間がかかっています。
6. クラスタの削除
HPAの動作がわかったところでEKSクラスタを削除していきます。
$ eksctl delete cluster \ --name=eksworkshop-hpa
Cluster Autoscaler(CA)を試す
次にCAを試していきます。今回はEKSWorkshopの手順とかなり違う順序でやっていますのでご了承ください。
HPAとは違いノードをスケールさせます。
またメトリクスもCPU使用率とかではなくpending状態のPodに基づいてスケールします。EKSの場合だとクラスタのメトリクスを元にASGに対して指示を出すことで実現します。
環境
- Kubernetes: 1.14
- eksctl: 0.10.2
1. クラスタの作成
eksctlを使って東京リージョンにさくさくっと作り上げます。
$ export AWS_DEFAULT_REGION=ap-northeast-1 $ eksctl create cluster \ --name=eksworkshop-eksctl \ --nodes=3 \ --node-type=t3.small
2. ASGの更新
eksctlで作成したASGを探して最小、最大量の変更を行います。
$ aws autoscaling update-auto-scaling-group \ --auto-scaling-group-name <ASG NAME> \ --min-size 2 \ --max-size 8
3. IAM Policyの作成
クラスタからAutoScalingの状態を変更確認できるように、IAMロールにポリシーを付与します。 なのでまず初めにポリシーファイルを作成します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "autoscaling:DescribeAutoScalingGroups", "autoscaling:DescribeAutoScalingInstances", "autoscaling:SetDesiredCapacity", "autoscaling:TerminateInstanceInAutoScalingGroup", "autoscaling:DescribeTags" ], "Resource": "*" } ] }
次にそのファイルを元にIAM Roleにアタッチします。
$ STACK_NAME=$(eksctl get nodegroup --cluster eksworkshop-eksctl -o json | jq -r '.[].StackName') $ INSTANCE_PROFILE_ARN=$(aws cloudformation describe-stacks --stack-name $STACK_NAME | jq -r '.Stacks[].Outputs[] | select(.OutputKey=="InstanceProfileARN") | .OutputValue') $ ROLE_NAME=$(aws cloudformation describe-stacks --stack-name $STACK_NAME | jq -r '.Stacks[].Outputs[] | select(.OutputKey=="InstanceRoleARN") | .OutputValue' | cut -f2 -d/) $ aws iam put-role-policy --role-name $ROLE_NAME --policy-name ASG-Policy-For-Worker --policy-document file://asg-policy.json
4. CAのデプロイ
CA用のServiceAccountの作成とDeploymentを作成します。
EKSWorkshop用に準備されたマニュフェストはありますが、一部変更が必要なので変更します。
少しわかりづらい記載で申し訳ないですが、<ASG NAME>
の部分を実際のASGの名前に書き換えてください。
$ curl -O https://eksworkshop.com/scaling/deploy_ca.files/cluster_autoscaler.yml $ sed -i "s/<AUTOSCALING GROUP NAME>/<ASG NAME>/" cluster_autoscaler.yml $ sed -i "s/us-west-2/ap-northeast-1/" cluster_autoscaler.yml
最後に出来上がったマニュフェストをデプロイします。
$ kubectl apply -f cluster_autoscaler.yml
5. スケールさせる
Nginxを使用したPodで、replicasの値を1にしたDeploymentをデプロイします。
まずはマニュフェストを記載していきます。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-to-scaleout spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: service: nginx app: nginx spec: containers: - image: nginx name: nginx-to-scaleout resources: limits: cpu: 500m memory: 512Mi requests: cpu: 500m memory: 512Mi
これをデプロイします。
$ kubectl apply -f nginx.yaml
この段階ではPod数が1つなので当然pendingも発生しておらずワーカーノードのスケールも発生していません。
$ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE nginx-to-scaleout 1/1 1 1 11s $ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-to-scaleout-84f9cdbd84-tsptk 1/1 Running 0 41s
ワーカーノードのスケールを発生させるためにDeploymentsのPod数をスケールさせます。
$ kubectl scale --replicas=10 deployment/nginx-to-scaleout
この段階でPodがpending状態になっていることが確認できます。
$ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-to-scaleout-84f9cdbd84-2tb9x 1/1 Running 0 32s nginx-to-scaleout-84f9cdbd84-8vvp7 1/1 Running 0 32s nginx-to-scaleout-84f9cdbd84-8w6fh 1/1 Running 0 32s nginx-to-scaleout-84f9cdbd84-kxx6p 1/1 Running 0 32s nginx-to-scaleout-84f9cdbd84-lkwth 1/1 Running 0 32s nginx-to-scaleout-84f9cdbd84-m2jfq 1/1 Running 0 32s nginx-to-scaleout-84f9cdbd84-rzvqr 1/1 Running 0 32s nginx-to-scaleout-84f9cdbd84-tsptk 1/1 Running 0 3m11s nginx-to-scaleout-84f9cdbd84-w4hj7 0/1 Pending 0 32s nginx-to-scaleout-84f9cdbd84-xmgvb 1/1 Running 0 32s
ワーカーノードのスケーリングが終わり4台に増えた段階でpendingが解消されることも確認できました。
$ kubectl get nodes NAME STATUS ROLES AGE VERSION ip-192-168-19-201.ap-northeast-1.compute.internal Ready <none> 33m v1.14.7-eks-1861c5 ip-192-168-48-242.ap-northeast-1.compute.internal Ready <none> 17m v1.14.7-eks-1861c5 ip-192-168-58-249.ap-northeast-1.compute.internal Ready <none> 33m v1.14.7-eks-1861c5 ip-192-168-77-50.ap-northeast-1.compute.internal Ready <none> 33m v1.14.7-eks-1861c5 $ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-to-scaleout-84f9cdbd84-2tb9x 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-8vvp7 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-8w6fh 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-kxx6p 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-lkwth 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-m2jfq 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-rzvqr 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-tsptk 1/1 Running 0 5m22s nginx-to-scaleout-84f9cdbd84-w4hj7 1/1 Running 0 2m43s nginx-to-scaleout-84f9cdbd84-xmgvb 1/1 Running 0 2m43s
Cluster AutoscalerでもHPAと同様に、スケーリングを行なった後の待機時間が設定されているのでそれが終わるまでノード数は減っていきません。
6. クラスタの削除
まずアタッチしたポリシーを削除してからクラスタを削除します。
$ aws iam delete-role-policy \ --role-name $ROLE_NAME \ --policy-name ASG-Policy-For-Worker $ eksctl delete cluster \ --name=eksworkshop-eksctl
さいごに
kubectlを実際に実行しながら進めるのでEKSWorkshopはEKSを理解するのに非常に良いチュートリアルです。 お手すきの際に実際にお試しください